package com.chw.utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.params.HttpMethodParams;

public class HttpUtils {

	private static LogUtil log = LogUtil.newInstance(HttpUtils.class);

	private final static int READ_TIMEOUT = 10000;

	public static Map<String, Object> sendRequest(String url, HttpServletRequest request) {

		//Get request mothod
		String requestMethod = request.getMethod();

		//Get request headers
		List<Header> headers = resolveHeaders(request);

		//Get request params
		List<NameValuePair> requestParams = resolveParams(request);

		return sendRequest(url,requestMethod,headers,requestParams);
	}

	public static Map<String, Object> sendRequest(String url, String requestMethod, List<Header> headerList, List<NameValuePair> nameValuePairList) {
		Header[] headers = new Header[]{};
		if(headerList!=null && !headerList.isEmpty()){
			int size = headerList.size();
			headers = headerList.toArray(new Header[size]);
		}

		NameValuePair[] requestParams = new NameValuePair[]{};
		if(nameValuePairList!=null && !nameValuePairList.isEmpty()){
			int size = nameValuePairList.size();
			requestParams = nameValuePairList.toArray(new NameValuePair[size]);
		}

		return sendRequest(url,requestMethod,headers,requestParams);
	}

	public static Map<String, Object> sendRequest(String url, String requestMethod, Header[] headers, NameValuePair[] requestParams) {

		log.debug(String.format("Request url:%s",url));

		log.debug(String.format("Request method:%s",requestMethod));

		log.debug(String.format("Request headers:%s",GsonUtils.GsonString(headers)));

		log.debug(String.format("Request params:%s",GsonUtils.GsonString(requestParams)));

		// Create a method instance.
		HttpMethod httpMethod = null;
		if (requestMethod.equals("GET")) {
			GetMethod getMethod = new GetMethod(url);
			if (requestParams != null)
				getMethod.setQueryString(requestParams);
			httpMethod = getMethod;
		} else if (requestMethod.equals("POST")) {
			PostMethod postMethod = new PostMethod(url);
			if (requestParams != null)
				postMethod.setRequestBody(requestParams);
			httpMethod = postMethod;
		}

		// Set request headers
		setHeaders(headers, httpMethod);

		return httpRequest(httpMethod);
	}

	public static Map<String,Object> sendPostRequestByBody(String url, HttpServletRequest request){
		log.debug(String.format("Request url:%s",url));
		try {
			PostMethod postMethod = new PostMethod(url);
			InputStream sis = request.getInputStream();
			BufferedReader reader = new BufferedReader(new InputStreamReader(sis));
			StringBuffer responseBody = new StringBuffer();
			String str = "";
			while ((str = reader.readLine())!=null) {
				responseBody.append(str);
			}
			log.debug(String.format("Request url:%s",url));
			log.debug(String.format("Request url:%s",url));
			postMethod.setRequestEntity(new StringRequestEntity(responseBody.toString(), request.getContentType(), request.getCharacterEncoding()));

			HttpMethod httpMethod = postMethod;

			setHeaders(request, httpMethod);

			return httpRequest(httpMethod);
		}catch (Exception e)
		{
			return null;
		}
	}

	public static Map<String, Object> sendPostRequest(String url, List<NameValuePair> nameValuePairList) {
		return sendRequest(url,"POST",setDefaultHeader(),nameValuePairList);
	}

	public static Map<String, Object> sendGetRequest(String url, List<NameValuePair> nameValuePairList) {
		return sendRequest(url,"GET",setDefaultHeader(),nameValuePairList);
	}

	private static Map<String,Object> httpRequest(HttpMethod httpMethod){

		Map<String, Object> res = null;

		HttpClient client = new HttpClient();

		//Set read timeout
		HttpMethodParams httpMethodParams = client.getParams();
		httpMethodParams.setSoTimeout(READ_TIMEOUT);

		try {
			// Execute the method.
			client.executeMethod(httpMethod);

			/*if (statusCode != HttpStatus.SC_OK) {
				System.err.println("Method failed: " + method.getStatusLine());
			}*/

			// Read the response body.
			//String responseBody = httpMethod.getResponseBodyAsString();
			res = new HashMap<String, Object>();

			if(httpMethod.getResponseBodyAsStream()!=null) {
				BufferedReader br = new BufferedReader(new InputStreamReader(httpMethod.getResponseBodyAsStream()));
				StringBuffer responseBody = new StringBuffer();
				String str = "";
				while ((str = br.readLine())!=null) {
					responseBody.append(str);
				}
				res.put("result", responseBody.toString());
			}

			// Deal with the response.
			// Use caution: ensure correct character encoding and is not binary data

			res.put("statusCode",httpMethod.getStatusCode());


			Header contentTypeHeader = httpMethod.getResponseHeader("Content-Type");
			if(contentTypeHeader!=null) {
				res.put("contentType", contentTypeHeader.getValue());
			}
		} catch (HttpException e) {
			log.error("Fatal protocol violation: " + e.getMessage());
			e.printStackTrace();
		} catch (IOException e) {
			log.error("Fatal transport error: " + e.getMessage());
			e.printStackTrace();
		} finally {
			// Release the connection.
			httpMethod.releaseConnection();
		}
		return res;
	}

	//设置请求头
	protected static void setHeaders(HttpServletRequest request, HttpMethod method) {
		//Get request headers
		List<Header> headerList = resolveHeaders(request);

		Header[] headers = new Header[]{};
		if(headerList!=null && !headerList.isEmpty()){
			int size = headerList.size();
			headers = headerList.toArray(new Header[size]);
		}

		// Set request headers
		setHeaders(headers, method);
	}

	// 设置请求头属性
	protected static void setHeaders(Header[] headers, HttpMethod method) {
		for(Header header : headers){
			method.setRequestHeader(header);
		}
	}

	// 解析请求头
	public static List<Header> resolveHeaders(HttpServletRequest request) {
		List<Header> headers = new ArrayList<Header>();
		Enumeration<String> headerNames = request.getHeaderNames();
		while (headerNames.hasMoreElements()) {
			String key = (String) headerNames.nextElement();
			String value = request.getHeader(key);
			headers.add(new Header(key,value));
		}
		headers.add(new Header("sendRequest","true"));
		return headers;
	}

	public static List<Header> setDefaultHeader(){
		List<Header> headers = new ArrayList<Header>();
		headers.add(new Header("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"));
		headers.add(new Header("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"));
		headers.add(new Header("Accept-Encoding","gzip, deflate, sdch"));
		headers.add(new Header("Accept-Language","zh-CN,zh;q=0.8"));
		headers.add(new Header("Cache-Control","max-age=0"));
		headers.add(new Header("Connection","keep-alive"));
		headers.add(new Header("Content-Type","application/x-www-form-urlencoded;charset=UTF-8"));
		return headers;
	}

	// 解析请求参数
	public static List<NameValuePair> resolveParams(HttpServletRequest request) {
		List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
		Enumeration<String> paramNames = request.getParameterNames();
		while (paramNames.hasMoreElements()) {
			String paramName = paramNames.nextElement();
			String value = request.getParameter(paramName);
			nameValuePairs.add(new NameValuePair(paramName,value));
		}
		return nameValuePairs;
	}

	//添加请求参数
	public static List<NameValuePair> addParams(List<NameValuePair> requestParams,Map<String,String> addParams){
		List<NameValuePair> nameValuePairs = requestParams;

		if(nameValuePairs == null)
		{
			nameValuePairs = new ArrayList<NameValuePair>();
		}

		if(addParams!=null)
		{
			Set<String> params = addParams.keySet();

			for(String param : params){
				nameValuePairs.add(new NameValuePair(param,addParams.get(param)));
			}
		}
		return nameValuePairs;
	}
}
